import schedule
import sqlalchemy
import tushare as ts
from datetime import datetime, time, date
import pandas as pd
from dao.real_dao import get_last_record,StockRealData,add_real_list,get_real_list_dao
import logging

token = 'f7fac7d93d700e5b3f2c586c958414763a742c0f74a60176749d0718'
ts.set_token(token)
pro = ts.pro_api()
logging.basicConfig(level = logging.DEBUG,format='%(asctime)s - %(levelname)s - %(message)s')


# 获取指定股票的日、周、月线数据，支持多股票，用逗号分隔
def get_stock_data(stock_code, freq='D'):
    df = None
    if freq == 'D':
        df = pro.daily(ts_code=stock_code)
    elif freq == 'W':
        df = pro.weekly(ts_code=stock_code)
    elif freq == 'M':
        df = pro.monthly(ts_code=stock_code)
    #  将交易日期转换为时间戳
    df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
    df['timestamp'] = (df['trade_date'].astype('int64') // 10**6).astype('int64')
    return df[['timestamp', 'open', 'high', 'low', 'close', 'vol',"trade_date"]].to_dict(orient='records')


# 获取实时涨跌幅排名数据(爬取时间较长，建议缓存)
def get_realtime_rank():
    df = ts.realtime_list(src='sina')
    return df


# 10个热门股票列表
# stock_codes = ['000001.SZ', '600519.SH', '000333.SZ', '600036.SH', '000651.SZ', '600276.SH', '300750.SZ', '600900.SH',
#                '000333.SZ', '002475.SZ']

stock_codes = [
    '000001.SH',
    "399001.SZ",
    "399006.SZ",
]



# 获取实时行情数据，每次获取一条数据,支持多股票，用逗号分隔
def get_realtime_quote_df():
    stock_str = ",".join(stock_codes)
    df = ts.realtime_quote(stock_str, src='sina')
    return df[['name', 'ts_code', 'date', 'time', 'open', 'pre_close', 'price', 'high', 'low', 'bid', 'ask', 'volume',
               'amount']]


def transform_data_for_kline(df):
    # 将 trade_date 列转换为时间戳（毫秒级）
    df['trade_date'] = pd.to_datetime(df['trade_date']).astype(int) / 10**6  # 转换为毫秒级时间戳
    return df[['trade_date', 'open', 'high', 'low', 'close', 'vol']].to_dict(orient='records')


# 获取股票实时行情数据，并存入数据库中
def fetch_data():
    # 如果今天不是交易日，不需要获取数据
    pre_trade_date,is_open = is_trading_day()
    if not is_open:
        return
    # 当前时间不是交易时间
    if not is_in_trading_hours():
        return

    # 获取当前时间并打印
    print(f"正在获取{datetime.now()}的数据")
    stock_str = ",".join(stock_codes)
    df = ts.realtime_quote(stock_str, src='sina')
    # 将列名转换为小写
    df.columns = df.columns.str.lower()
    df = df[['name', 'ts_code', 'date', 'time', 'open', 'pre_close', 'price', 'high', 'low', 'bid', 'ask', 'volume','amount']]
    real_list = []
    for row in df.itertuples():
        print(row)
        date_obj = datetime.strptime(row.date, '%Y%m%d').date()
        time_obj = datetime.strptime(row.time, '%H:%M:%S').time()
        # 将日期对象和时间对象合并为一个datetime对象
        datetime_obj = datetime.combine(date_obj, time_obj)

        # 根据row创建一个对应的StockRealData对象
        stock_real_data = StockRealData()
        stock_real_data.ts_code = row.ts_code
        stock_real_data.datetime = datetime_obj
        stock_real_data.open = row.open
        stock_real_data.pre_close = row.pre_close
        stock_real_data.price = row.price
        stock_real_data.high = row.high
        stock_real_data.low = row.low
        stock_real_data.volume = row.volume
        stock_real_data.amount = row.amount

        # 计算当前相较于上一次的增长值和增长率
        # 9点30
        nine_30 = time(9,0)
        # 9点31
        nine_31 = time(9,1)
        # 如果是今天第一次获取数据，清空昨日数据，以昨日收盘价计算此次涨跌额和涨跌幅
        increase,ratio = 0,0
        if nine_31 <= time_obj <= nine_30:
            increase = row.price - row.pre_close
        else:
            last_record = get_last_record(row.ts_code)
            if last_record:
                increase = row.price - last_record.price
            else:
                increase = row.price - row.pre_close
        stock_real_data.increase = round(increase,8)
        stock_real_data.ratio = round(increase / row.price, 8)
        # print(stock_real_data)
        real_list.append(stock_real_data)
    # 清空前一天的实时数据记录？？

    add_real_list(real_list)
    # 这里可以将数据发送到前端或保存到数据库等
    print("获取并存入数据库成功")

# 返回上一个交易日期，已经今天是否是交易日
def is_trading_day():
    today = datetime.now().strftime('%Y%m%d')
    df = pro.trade_cal(exchange='', start_date=today, end_date=today)
    row = df.iloc[0]
    return row.pretrade_date,row.is_open == 1

# 判断当前时间是否是交易时间
def is_in_trading_hours():
    now = datetime.now()
    start_morning = now.replace(hour = 9, minute = 30, second = 0, microsecond = 0)
    end_morning = now.replace(hour = 11, minute = 30, second = 0, microsecond = 0)
    start_afternoon = now.replace(hour = 13, minute = 0, second = 0, microsecond = 0)
    end_afternoon = now.replace(hour = 15, minute = 0, second = 0, microsecond = 0)
    if (start_morning <= now <= end_morning) or (start_afternoon <= now <= end_afternoon):
        return True
    else:
        return False


#  获取当前某只股票的实时数据
# 1：如果今天是交易日，且当前未开盘，返回上一个交易日数据；开盘后返回当天实时交易数据
# 2：当前不是交易日，返回上一个交易日实时数据
def get_real_list(ts_code:str):
    pre_trade_date_str,is_open = is_trading_day()
    pre_trade_date = datetime.strptime(pre_trade_date_str, "%Y%m%d").date()
    real_list = []
    if is_open:
        now = datetime.now()
        start_morning = now.replace(hour=9, minute=30, second=0, microsecond=0)
        if now <= start_morning:
            real_list = get_real_list_dao(ts_code,pre_trade_date)
        else:
            real_list = get_real_list_dao(ts_code,date.today())
    else:
        real_list = get_real_list_dao(ts_code,pre_trade_date)
    return real_list


def get_point_real_data(code_list):
    stock_str = ",".join(code_list)
    df = ts.realtime_quote(stock_str, src='sina')
    # 将列名转换为小写
    df.columns = df.columns.str.lower()
    df = df[['name', 'ts_code', 'date', 'time', 'open', 'pre_close', 'price', 'high', 'low', 'bid', 'ask', 'volume','amount']]
    print(df)
    return df.to_dict(orient='records')

def fetch_job():
    logging.info("获取指数实时信息")
    times = 1
    success_flag = False
    # 进行异常判断，最多尝试5次
    while times <= 5 and not success_flag:
        try:
            logging.info(f"尝试第{times}次获取实时行情数据")
            fetch_data()
            success_flag = True
        except Exception as e:
            logging.debug(e)
            times += 1


# 设置每天的定时任务（每分钟调用一次）
schedule.every(1).minute.at(":01").do(fetch_job)

# fetch_data()

# results = get_real_list("600519.SH")
# for real_data in results:
#     print(real_data)




